﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace DnDLib
{
    public class Connection: ThreadSafeMethods
    {
        delegate void callback(Connection conn);

        string Version = string.Format("2.0.0");
        const int MAX_RECEIVE_BYTES = 1024;       

        bool _receivingFile = false;
        byte[] _buffer = new byte[MAX_RECEIVE_BYTES];
        List<byte> _receiveQueue = new List<byte>();
        Queue<Packet> _packetQueue = new Queue<Packet>();
        Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint _ipEnd;
      
        callback onReceive;

        #region Constructors

        public Connection(string ip, int port, bool autoConnect)
        {
            _ipEnd = new IPEndPoint(IPAddress.Parse(ip), port);

            if (autoConnect)
            {
                Connect();
            }
        }

        #endregion

        public void Connect()
        {
            _socket.Connect(_ipEnd);
            _socket.BeginReceive(_buffer, 0, MAX_RECEIVE_BYTES, 0, new AsyncCallback(ReceiveComplete), this);
        }

        /*
         * Callback method for asynchronous receive
         */
        public void ReceiveComplete(IAsyncResult ar)
        {
            int bytesReceived = 0;

            try
            {
                bytesReceived = _socket.EndReceive(ar);
            }
            catch
            {
            }

            AddRange(_receiveQueue, Splice(_buffer, 0, bytesReceived));
            
            string s = Encoding.ASCII.GetString(_buffer, 0, bytesReceived);

#if DEBUG
            Debug.WriteLine(string.Format("{0} Received from {1}: {2}", DateTime.Now, _socket.RemoteEndPoint, s));
#endif
            onReceive.Invoke(this);

            try
            {
                _socket.BeginReceive(_buffer, 0, 1024 * MAX_RECEIVE_BYTES, 0, new AsyncCallback(ReceiveComplete), this);
            }
            catch (Exception e)
            {
#if DEBUG
                Debug.WriteLine(string.Format("{0} Exception on receive {1}: {2}", DateTime.Now, _socket.RemoteEndPoint, e));
#endif
                throw e;
            }
        }
    }
}
